package com.yunchao.feature.business.data.repository

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.yunchao.feature.base.data.CacheManager
import com.yunchao.feature.base.domain.constants.DEVICE_NUMBER_KEY
import com.yunchao.feature.base.domain.constants.LOOP_POWER_KEY
import com.yunchao.feature.base.domain.constants.SINGLE_POWER_KEY
import com.yunchao.feature.base.domain.result.createException
import com.yunchao.feature.business.data.datasource.api.BusinessService
import com.yunchao.feature.business.data.datasource.api.mapper.toDomainModel
import com.yunchao.feature.business.data.datasource.api.mapper.toEntityModel
import com.yunchao.feature.business.data.datasource.api.request.BusinessRequest
import com.yunchao.feature.business.data.datasource.api.request.getMIMISIF002RequestInfo
import com.yunchao.feature.business.data.datasource.api.request.getMIMISIF004RequestInfo
import com.yunchao.feature.business.data.datasource.api.request.getMIMISIF006RequestInfo
import com.yunchao.feature.business.data.datasource.api.request.getMIMISIF008RequestInfo
import com.yunchao.feature.business.data.datasource.api.response.BusinessResponse
import com.yunchao.feature.business.data.datasource.database.BusinessInfoDao
import com.yunchao.feature.business.data.datasource.database.model.toDomainModel
import com.yunchao.feature.business.domain.enum.BusinessType
import com.yunchao.feature.business.domain.model.BusinessInfoModel
import com.yunchao.feature.business.domain.model.BusinessPackModel
import com.yunchao.feature.business.domain.model.createPackInfoByLock
import com.yunchao.feature.business.domain.model.getPackInfoByLock
import com.yunchao.feature.business.domain.model.toEntityModel
import com.yunchao.feature.business.domain.repository.BusinessRepository
import com.yunchao.library.http.ApiResult
import com.yunchao.library.lock.DeviceHelper
import com.yunchao.library.lock.IDeviceHelper
import com.yunchao.library.lock.IDeviceHelper.Companion.SINGLE_SCAN_POWER
import com.yunchao.library.lock.LockEPCInfo
import com.yunchao.library.lock.getLockStatus
import com.yunchao.library.lock.getLockStatusStr
import com.yunchao.library.lock.getVoucherTypeValue
import kotlinx.coroutines.flow.Flow
import timber.log.Timber
import java.math.BigDecimal
import kotlin.collections.map
import com.yunchao.feature.business.data.datasource.api.model.CommonApiModel
import com.yunchao.feature.business.data.datasource.api.model.FileTaskApiModel
import kotlinx.coroutines.flow.mapNotNull

internal class BusinessRepositoryImpl(
    private val businessService: BusinessService,
    private val businessInfoDao: BusinessInfoDao,
    private val deviceHelper: DeviceHelper,
    private val gson: Gson
) : BusinessRepository {

    override suspend fun getBusinessInfo(businessRequest: BusinessRequest): Result<BusinessInfoModel> {
        Timber.d("获取业务信息请求参数：$businessRequest")
        return when (val apiResult = businessService.businessRequestAsync(businessRequest)) {
            is ApiResult.Success -> if (apiResult.data.success()) {
                businessInfoDao.deleteAll().let {
                    handleSuccessResult(apiResult.data)
                }
            } else {
                Result.failure(createException(apiResult.data.respMessage))
            }

            is ApiResult.Error -> Result.failure(createException(apiResult.message))

            is ApiResult.Exception -> {
                businessInfoDao.query()?.let {
                    Result.success(it.toDomainModel())
                } ?: Result.failure(apiResult.throwable)
            }
        }
    }


    override suspend fun getBusinessInfo(
        tranTypeID: String,
        tranID: String
    ): Result<BusinessInfoModel> = businessInfoDao.query(tranTypeID, tranID)?.let {
        Result.success(it.toDomainModel())
    } ?: Result.failure(createException("未查询到业务信息"))


    override suspend fun setupPower(isLoop: Boolean): Result<Boolean> = runCatching {
        val power = if (isLoop) CacheManager.getString(LOOP_POWER_KEY) else CacheManager.getString(
            SINGLE_POWER_KEY
        )
        deviceHelper.setPower(power = power?.toIntOrNull() ?: SINGLE_SCAN_POWER)
    }

    override suspend fun inventoryOnce(
        businessInfoModel: BusinessInfoModel,
        packInfoMap: Map<String, BusinessPackModel>
    ): Result<BusinessPackModel> = runCatching {
        deviceHelper.inventoryOnce()
    }.mapCatching {
        processLockEPCInfo(it, businessInfoModel, packInfoMap)
    }

    override suspend fun inventoryLoop(
        businessInfoModel: BusinessInfoModel,
        packInfoMap: Map<String, BusinessPackModel>
    ): Flow<List<BusinessPackModel>> = deviceHelper.inventoryLoop()
        .mapNotNull { lockEPCInfoList ->
            if (lockEPCInfoList.isNotEmpty()) {
                Timber.i("BusinessRepositoryImpl  inventoryLoop:  $lockEPCInfoList")
            }
            processLockEPCInfoList(lockEPCInfoList, businessInfoModel, packInfoMap)
        }


    override suspend fun inventoryStop(
        taskInfo: BusinessInfoModel, payloads: List<BusinessPackModel>, isLoop: Boolean
    ) {
        if (isLoop) {
            deviceHelper.inventoryStop()
        }
        // 尝试获取任务信息并更新
        businessInfoDao.query(taskInfo.tranTypeID, taskInfo.tranID)?.apply {
            Timber.d("更新任务 handleInventoryStop : $this")
            // 将 payloads 转换为实体模型
            businessInfoDao.update(copy(packInfoPayloads = payloads.map { it.toEntityModel() }))
        }
    }

    override suspend fun closeLockWriteLogistics(
        taskInfo: BusinessInfoModel,
        packInfo: BusinessPackModel,
        busiInfo: BusinessPackModel,
        pageNumber: Int
    ): Result<BusinessPackModel> = runCatching {
        deviceHelper.closeLockWriteLogistics(
            lockEPCInfo = packInfo.lockEPCInfo!!,
            deviceId = CacheManager.getString(DEVICE_NUMBER_KEY)?.toIntOrNull()
                ?: IDeviceHelper.DEFAULT_DEVICE_ID,
            pageNumber = pageNumber,
            operatorId = getOperatorId(taskInfo),
            chkUserId = getChkUserId(taskInfo)
        )
    }.mapCatching {
        packInfo.getPackInfoByLock(
            tranTypeId = taskInfo.tranTypeID,
            lockEPCInfo = it,
            busiInfo = busiInfo
        )
    }

    override suspend fun openLockWriteLogistics(
        packInfoMap: Map<String, BusinessPackModel>,
        taskInfo: BusinessInfoModel
    ): Result<BusinessPackModel> = runCatching {
        deviceHelper.inventoryOnce()
    }.mapCatching { lockEPCInfo ->
        val packInfo = packInfoMap[lockEPCInfo.id]
            ?: throw IllegalStateException("锁号：${lockEPCInfo.id} 与业务信息不匹配或已扫描!!!")

        val result = deviceHelper.openLockWriteLogistics(
            lockEPCInfo = lockEPCInfo,
            deviceId = CacheManager.getString(DEVICE_NUMBER_KEY)?.toIntOrNull()
                ?: IDeviceHelper.DEFAULT_DEVICE_ID,
            operatorId = getOperatorId(taskInfo),
            chkUserId = getChkUserId(taskInfo),
            pageNumber = 0
        )
        packInfo.getPackInfoByLock(tranTypeId = taskInfo.tranTypeID, lockEPCInfo = result)
    }

    override suspend fun submitBusiness(
        businessInfoModel: BusinessInfoModel,
        items: List<BusinessPackModel>
    ): Result<String> = when (val apiResult = businessService.businessRequestAsync(
        getSubmitBusinessReq(
            taskInfo = businessInfoModel,
            items = items
        )
    )) {
        is ApiResult.Success -> if (apiResult.data.success()) {
            Result.success(apiResult.data.respMessage)
        } else {
            Result.failure(IllegalStateException(apiResult.data.respMessage))
        }

        is ApiResult.Error -> Result.failure(IllegalStateException(apiResult.message))

        is ApiResult.Exception -> Result.failure(apiResult.throwable)
    }


    private suspend fun handleSuccessResult(businessResponse: BusinessResponse) = runCatching {
        val tranTypeId = businessResponse.tranTypeId
        gson.fromJson(businessResponse.respMessage, CommonApiModel::class.java)?.let { business ->
            val businessEntityModel = businessInfoDao.query(tranTypeId, business.tranID.orEmpty())
            Timber.d("查询到数据库保存的信息：$businessEntityModel")
            businessEntityModel?.toDomainModel()
                ?: businessInfoDao.insert(business.toEntityModel()).let {
                    business.toDomainModel()
                }
        } ?: throw createException("业务信息为空")
    }


    private suspend fun handleFileSuccessResult(businessResponse: BusinessResponse) = runCatching {
        val tranTypeId = businessResponse.tranTypeId
        val type = object : TypeToken<List<FileTaskApiModel>>() {}.type
        toEntityModel(gson.fromJson(businessResponse.respMessage, type)).let { business ->
            val businessEntityModel = businessInfoDao.query(tranTypeId, business.tranID)
            if (businessEntityModel == null) {
                businessInfoDao.insert(business).let {
                    business.toDomainModel()
                }
            } else {
                businessEntityModel.toDomainModel()
            }
        }
    }


    /**
     * 处理提交任务的请求
     */
    private fun getSubmitBusinessReq(
        taskInfo: BusinessInfoModel,
        items: List<BusinessPackModel>
    ): BusinessRequest = when (taskInfo.tranTypeID) {
        BusinessType.BusinessTypeMIMISIF001.type -> getMIMISIF002RequestInfo(
            gson,
            taskInfo,
            items
        )

        BusinessType.BusinessTypeMIMISIF003.type -> getMIMISIF004RequestInfo(
            gson,
            taskInfo,
            items
        )

        BusinessType.BusinessTypeMIMISIF005.type -> getMIMISIF006RequestInfo(
            gson,
            taskInfo,
            items
        )

        BusinessType.BusinessTypeMIMISIF007.type -> getMIMISIF008RequestInfo(
            gson,
            taskInfo,
            items
        )

        else -> BusinessRequest(
            tranTypeId = BusinessType.BusinessTypeMIMISIF100.type,
            message = BusinessType.BusinessTypeMIMISIF100.describe
        )
    }

    /**
     * 获取列表展示的信息
     */
    private fun processLockEPCInfo(
        lockEPCInfo: LockEPCInfo,
        taskInfo: BusinessInfoModel,
        packInfoMap: Map<String, BusinessPackModel>
    ): BusinessPackModel {
        Timber.d("taskInfo = $taskInfo , lockEPCInfo = $lockEPCInfo , packInfoMap = $packInfoMap")
        val tranTypeId = taskInfo.tranTypeID
        when (tranTypeId) {
            BusinessType.BusinessTypeMIMISIF001.type -> {
                require(!packInfoMap.containsKey(lockEPCInfo.id)) {
                    "锁号：${lockEPCInfo.id} 与业务信息不匹配或已扫描!!!"
                }
                require("00" == lockEPCInfo.getLockStatus()) {
                    "锁号：${lockEPCInfo.id} 的包装袋状态为 ${lockEPCInfo.getLockStatusStr()}，请检查!!!"
                }
                require(taskInfo.busiInfoList.isEmpty() || taskInfo.busiInfoList.any {
                    BigDecimal(it.value).compareTo(BigDecimal(lockEPCInfo.getVoucherTypeValue())) == 0
                }) {
                    "锁号：${lockEPCInfo.id} 的面额为：${lockEPCInfo.getVoucherTypeValue()} 与业务信息不匹配!!!"
                }
            }

            BusinessType.BusinessTypeMIMISIF007.type -> {
                require(packInfoMap.containsKey(lockEPCInfo.id)) {
                    "锁号：${lockEPCInfo.id} 与业务信息不匹配或已扫描!!!"
                }
                require("01" == lockEPCInfo.getLockStatus()) {
                    "锁号：${lockEPCInfo.id} 的包装袋状态为 ${lockEPCInfo.getLockStatusStr()}，请检查!!!"
                }
            }

            else -> {
                require(packInfoMap.containsKey(lockEPCInfo.id)) {
                    "锁号：${lockEPCInfo.id} 与业务信息不匹配或已扫描!!!"
                }
            }
        }

        return if (BusinessType.BusinessTypeMIMISIF001.type == tranTypeId) {
            taskInfo.busiInfoList.find {
                BigDecimal(it.value).compareTo(BigDecimal(lockEPCInfo.getVoucherTypeValue())) == 0
            }?.getPackInfoByLock(tranTypeId = tranTypeId, lockEPCInfo = lockEPCInfo)
                ?: createPackInfoByLock(lockEPCInfo)
        } else {
            packInfoMap[lockEPCInfo.id]?.getPackInfoByLock(
                tranTypeId = tranTypeId,
                lockEPCInfo = lockEPCInfo,
                handleResult = BusinessType.BusinessTypeMIMISIF003.type != tranTypeId
            ) ?: throw IllegalArgumentException("未找到锁号 ${lockEPCInfo.id} 对应的 PackInfo")
        }
    }


    /**
     * 获取列表展示的信息
     */
    private fun processLockEPCInfoList(
        lockEPCInfoList: List<LockEPCInfo>,
        business: BusinessInfoModel,
        packInfoMap: Map<String, BusinessPackModel>
    ): List<BusinessPackModel> {
        val tranTypeID = business.tranTypeID
        // 根据 tranTypeID 查找符合条件的 lockEPCInfo
        val matchingLockEPCInfoList = lockEPCInfoList.filter { lockEPCInfo ->
            when (tranTypeID) {
                BusinessType.BusinessTypeMIMISIF001.type -> lockEPCInfo.getLockStatus() == "00" && !packInfoMap.containsKey(
                    lockEPCInfo.id
                )

                BusinessType.BusinessTypeMIMISIF007.type -> lockEPCInfo.getLockStatus() == "01" && packInfoMap.containsKey(
                    lockEPCInfo.id
                )

                else -> packInfoMap.containsKey(lockEPCInfo.id)
            }
        }

        return when (tranTypeID) {
            BusinessType.BusinessTypeMIMISIF001.type -> {
                // 如果 tranTypeID 匹配 TaskTypeMIMISIF001.type
                if (business.busiInfoList.isEmpty()) {
                    matchingLockEPCInfoList.map { createPackInfoByLock(it) }
                } else {
                    business.busiInfoList.mapNotNull { packInfo ->
                        matchingLockEPCInfoList.firstOrNull { lockEPCInfo ->
                            BigDecimal(packInfo.value).compareTo(BigDecimal(lockEPCInfo.getVoucherTypeValue())) == 0
                        }?.let { lockEPCInfo ->
                            packInfo.getPackInfoByLock(
                                tranTypeId = tranTypeID,
                                lockEPCInfo = lockEPCInfo
                            )
                        }
                    }
                }
            }

            else -> {
                // 其他情况
                matchingLockEPCInfoList.mapNotNull { lockEPCInfo ->
                    packInfoMap[lockEPCInfo.id]?.getPackInfoByLock(
                        tranTypeId = tranTypeID,
                        lockEPCInfo
                    )
                }
            }
        }
    }


    /**
     * 获取操作人
     */
    private fun getOperatorId(taskInfo: BusinessInfoModel): Int {
        val operatorId = taskInfo.giveOperator

        return when {
            operatorId.isBlank() -> 0
            operatorId.length > 8 -> operatorId.substring(0, 8).toIntOrNull() ?: 0
            else -> operatorId.toIntOrNull() ?: 0
        }
    }


    /**
     * 获取授权人
     */
    private fun getChkUserId(taskInfo: BusinessInfoModel): Int {
        val chkUserId = taskInfo.chkUserId

        return when {
            chkUserId.isBlank() -> 0
            chkUserId.length > 8 -> chkUserId.substring(0, 8).toIntOrNull() ?: 0
            else -> chkUserId.toIntOrNull() ?: 0
        }
    }
}